﻿/**
 * 
 * Copyright 2009, 2010 Mike Jamer [email: mikejamer@gmail.com ]
 * 
 * This File is part of Moose IRC
 * 
 * MooseIRC is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * MooseIRC is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with MooseIRC.  If not, see <http://www.gnu.org/licenses/>.
 * 
 */

using System;
using System.Collections.Generic;
using moose.irc.extension;

namespace moose.irc {
    // <summary>
    /// This is an IRC Session
    /// </summary>
    [CLSCompliant(true)]
    public class IrcSession {

        #region [Local Attributes]

        /// <summary>
        /// Connection to IRC Server 
        /// </summary>
        private IrcConnection m_connection;

        /// <summary>
        /// Internal Address List 
        /// </summary>
        private IrcEntityList m_InternalAddressList;

        /// <summary>
        /// Current State 
        /// </summary>
        private IrcSessionStates m_currentState;

        /// <summary>
        /// Session Settings
        /// </summary>
        private Dictionary<IrcSessionSettings, object> m_session_settings;

        /// <summary>
        /// Server Settings
        /// </summary>
        private Dictionary<IrcServerSettings, object> m_server_settings;

        #endregion

        #region [Internal Properties]

        /// <summary>
        /// Provides a point of access for actions to affect
        /// the connection object directly.
        /// </summary>
        internal IrcConnection Connection {
            get {
                return m_connection;
            }
            set {
                m_connection = value;
                return;
            }
        }

        #endregion

        #region [Public Properties]

        /// <summary>
        /// Gets/Sets Current Session State
        /// </summary>
        public IrcSessionStates SessionState {
            get {
                return m_currentState;
            }
            set {
                m_currentState = value;
                return;
            }
        }

        /// <summary>
        /// Gets/Sets Server Settings
        /// </summary>
        public Dictionary<IrcServerSettings, object> Settings_Server {
            get {
                return m_server_settings;
            }
            set {
                m_server_settings = value;
                return;
            }
        }

        /// <summary>
        /// Gets/Sets Session Settings
        /// </summary>
        public Dictionary<IrcSessionSettings, object> Settings_Session {
            get {
                return m_session_settings;
            }
            set {
                m_session_settings = value;
                return;
            }
        }

        #endregion

        #region [Events]

        /// <summary>
        ///  Signal indicates an irc event
        /// </summary>
        public event IrcEventHandler Event;

        #endregion

        #region [Construction]

        /// <summary>
        /// Initialize IRC Session 
        /// </summary>
        public IrcSession()
            : base() {
            m_currentState = IrcSessionStates.Disconnected;
            m_connection = new IrcConnection();
            m_InternalAddressList = new IrcEntityList();

            m_server_settings = new Dictionary<IrcServerSettings, object>();
            m_session_settings = new Dictionary<IrcSessionSettings, object>();

            m_connection.Response += onServerResponse;
            Event += onIrcEvent;

            return;
        }

        #endregion

        #region [Public Methods]

        /// <summary>
        /// Send Data to server,
        /// actually, attempt to lookup a command and use that first. 
        /// </summary>
        /// <param name="message">
        /// A <see cref="System.String"/>
        /// Message/Command to send to the server
        /// </param>
        public void send(string input) {
            IrcMessage message = new IrcMessage(input);
            IrcAction action = ExtensionManager.get_action(ActionTypes.Command, message.Command);
            if (action == null)
                send_raw(input);
            else
                action.execute(this, message);
            return;
        }

        /// <summary>
        /// Send Data directly to the server, as-is,
        /// don't even attempt to find a command
        /// </summary>
        /// <param name="message">
        /// A <see cref="System.String"/>
        /// Message/Command to send to the server
        /// </param>
        public void send_raw(string message) {
            m_connection.send(message);
            return;
        }

        /// <summary>
        /// Gets/Looks-up IRC Entity, either a user or a channel
        /// </summary>
        /// <param name="entity_string">
        /// A <see cref="System.String"/>,
        /// this is either a channel name, a nickname or a BNF host string
        /// </param>
        /// <returns>
        /// A <see cref="IrcEntity"/>
        /// </returns>
        public IrcEntity get_entity(string entity_string) {
            return m_InternalAddressList.get(entity_string);
        }

        /// <summary>
        /// Notify of an Event 
        /// </summary>
        /// <param name="irc_event">
        /// A <see cref="IrcEvent"/>
        /// </param>
        public void notify_event(IrcEvent irc_event) {
            Event(this, irc_event);
            return;
        }

        #endregion

        #region [Event Handlers]

        /// <summary>
        /// Fires when server responds with a message of sorts 
        /// </summary>
        /// <param name="response">
        /// A <see cref="System.String"/>
        /// </param>
        private void onServerResponse(string response) {
            dispatch(new IrcMessage(response));
            return;
        }

        /// <summary>
        /// Handles IRC Events 
        /// </summary>
        /// <param name="session">
        /// A <see cref="IrcSession"/>
        /// </param>
        /// <param name="irc_event">
        /// A <see cref="IrcEvent"/>
        /// </param>
        private void onIrcEvent(IrcSession session, IrcEvent irc_event) {
            return;
        }

        #endregion

        #region [Message Processing]

        /// <summary>
        /// Process recieved message from server
        /// </summary>
        /// <param name="message">parsed message</param>
        private void dispatch(IrcMessage message) {
            if (message.Command == null) //If the message was not parsed correctly
                return; //Ignore it, quietly
            IrcAction action = ExtensionManager.get_action(ActionTypes.Response, message.Command);
            if (action != null) { //If a response-action has been found...
                action.execute(this, message); //execute that action
            } else {
                notify_event(IrcEvent.createEchoEvent(message.ToString()));
            }
            return;
        }

        #endregion

    }
}
